#include <stdlib.h>

#include "lib.h"
#include "vpsql.h"
#include "vpsaved.h"
#include "vpopts.h"
#include "odbc.h"
#include "missinggamenums.h"
#include "log.h"

VPokerSQL::VPokerSQL( const String&	DBDSN, const String& DBLogin,const String&	DBPassword)
:	TrackSQL(DBDSN, DBLogin, DBPassword)
{
#ifdef USE_MISSINGGAMENUMS
	//missing game nums deleted in TrackSQL::~TrackSQL
	missinggamenums = new MissingGameNums(this, "pub_getTableIdentityBlackjack");
#endif
}

int32
VPokerSQL::getOptions(VPokerOpts* opts, uint8 machId, uint8 nHands, int32 creditValue)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

    localCurrency lc;

	ok = getLocale(&lc) == NoError;

    if (!ok)
    {
        return ok;
    }

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
		query->define("exec pub_MHVPokerGetOptions ");
		query->addParam(machId, ODBCQuery::BINARY);
		query->addParam(creditValue);
        query->addParam(lc.int_curr_symbol);
		query->addParam(nHands);

		if (query->exec())
		{
			opts->payFreq = VPokerOpts::LO;
			opts->dblUpEnabled = false;

			while (query->getRow())
			{
				ok =
					query->getData(1, &opts->payFreq) &&
					query->getData(2, &opts->dblUpEnabled);
			}
		}
		delete query;
	}

	//psharpless 10/20/06
	//Case: 11052  New Double Up Win Cap Logic

	//get the new global options data
	if(ok)
	{
        query = conn->query();
        if (query)
        {
			query->define("exec pub_VPokerGetOptionsGlobal ");

			if (query->exec())
			{
				while (query->getRow())
				{
					ok = query->getData(1, &opts->dlbUpCapAmount);
				}
			}
			delete query;
		}
	}

	// psharpless #15914  11/01/06
    // Get the list of supported credit values.
    if(ok)
    {
        query = conn->query();
        if (query)
        {
            query->define("exec pub_MHVPokerGetCreditValues ");
			query->addParam(lc.int_curr_symbol);

            if (query->exec())
            {
                int nCount=0;

                // get the 5 (and ONLY 5) credit values.
                while (ok && nCount<5 && query->getRow())
                {
                    ok = query->getData(1, &opts->anCreditValues[nCount++]);                    
                }

                if(nCount!=5)
                {
                    ok=false;
                }
            }
            delete query;
        }
    }
	delete conn;

	if (ok &&
		opts->payFreq >= VPokerOpts::LO &&
		opts->payFreq <= VPokerOpts::CUSTOM)	// CSN-6225
		return NoError;
	else
		return ExecFailed;
}

int32
VPokerSQL::getPlayerLimits(const PID& pid, int32 gameId, uint8 machId,
	int32* compFactor)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
		query->define("exec pub_lim_getPlayerLimits ");
		query->addParam(pid);
		query->addParam(gameId);
		query->addParam(machId, ODBCQuery::BINARY);

		if (query->exec())
		{
			while (query->getRow())
			{
				ok = query->getData(4, compFactor);
			}
		}
		delete query;
	}
	delete conn;

	return ok ? isGameEnabled(gameId,machId) : ExecFailed;
}

int32
VPokerSQL::createGame(
	int32 casinoId, const PID& pid, VPokerGameID gid, uint8 machineID,
	bool8 forMoney, SESSIONID sessionId, int32 compFactor,
	int32 bet, int32 numDealt, uint8* dealt,
	uint8 nHands, int32 creditValue, VPokerSavedGame* saved,
	int32 *balance, int32* comp)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;
	int32 result=0;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
		query->define("exec pub_CreateGameMHVPoker ");
		query->addParam(casinoId);
		query->addParam(pid);
		query->addParam(machineID, ODBCQuery::BINARY);
		query->addParam(nHands);
		query->addParam((bool8)(forMoney != 0));
		query->addParam(sessionId, ODBCQuery::NOQUOTES);
		query->addParam(compFactor);
		//
		// new game info
		//
		query->addParam(bet, ODBCQuery::MONEY);
		query->addParam(dealt, numDealt, ODBCQuery::BINARY);
		//
		// saved game info
		//
		query->addParam(creditValue);
		query->addParam((int32)saved->shue.seed);
		query->addParam(saved->shue.next);
		query->addParam((int32)saved->payFreq);
		query->addParam((bool8)(saved->dblUpEnabled != 0));

		if (query->exec())
		{
			while (query->getRow())
			{
				ok =
					query->getData(1, &result) &&
					query->getData(2, gid, VPOKER_GAMEID_SIZE) &&
					query->getData(3, balance, ODBCQuery::MONEY) &&
					query->getData(4, comp);
			}
		}
		delete query;
	}
	delete conn;

	if (ok && result == 0)
	{

#ifdef USE_MISSINGGAMENUMS
		int32 gamenum = atol(gid);
		if (missinggamenums)
			missinggamenums->setGameNum(gamenum);
#endif
		
		return NoError;
	}
	else if (ok && result == -1)
		return NotEnoughMoney;
	else
		return ExecFailed;
}

int32
VPokerSQL::drawHand(uint8 nhand, VPokerGameID gid, 
	int32 numDrawn, uint8* drawn,
	int32 payout, int32 paytype )
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;
	int32 result=0;

	conn = getConn();
	if (!conn)
		return NoConnection;
	
	query = conn->query();
	if (query)
	{
		query->define("exec pub_MHVPokerDrawHand ");
		query->addParam(nhand);
		query->addParam(gid, ODBCQuery::NOQUOTES);
		query->addParam(drawn, numDrawn, ODBCQuery::BINARY);
		query->addParam(payout, ODBCQuery::MONEY);
		query->addParam((uint8)(paytype & 0xffL), ODBCQuery::BINARY);

		if (query->exec())
		{
			while (query->getRow())
			{
				ok =query->getData(1, &result) ;
			}
		}
		delete query;
	}
	delete conn;

	return ok && result == 0 ? NoError : ExecFailed;
}

int32
VPokerSQL::drawHandRollBack( VPokerGameID gid)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;
	int32 result=0;

	conn = getConn();
	if (!conn)
		return NoConnection;
	
	query = conn->query();
	if (query)
	{
		query->define("exec pub_MHVPokerDrawHandRollBack ");
		query->addParam(gid, ODBCQuery::NOQUOTES);

		if (query->exec())
		{
			while (query->getRow())
			{
				ok =query->getData(1, &result) ;
			}
		}
		delete query;
	}
	delete conn;

	return ok && result == 0 ? NoError : ExecFailed;
}

int32
VPokerSQL::drawDone(
	int32 casinoId, const PID& pid, VPokerGameID gid, uint8 machineID,
	bool8 forMoney, int32 creditValue,
	int32 payout, 
	bool8 dblUpActive,
	int32* balance, int32* comp)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;
	int32 result=0;

	conn = getConn();
	if (!conn)
		return NoConnection;
	
	query = conn->query();
	if (query)
	{
		query->define("exec pub_MHVPokerDrawDone ");
		query->addParam(casinoId);
		query->addParam(pid);
		query->addParam(machineID, ODBCQuery::BINARY);
		query->addParam((bool8)(forMoney != 0));
		query->addParam(creditValue);
		query->addParam(gid, ODBCQuery::NOQUOTES);
		query->addParam(payout, ODBCQuery::MONEY);
		query->addParam((bool8)(dblUpActive != 0));

		if (query->exec())
		{
			while (query->getRow())
			{
				ok =
					query->getData(1, &result) &&
					query->getData(2, balance, ODBCQuery::MONEY) &&
					query->getData(3, comp);
			}
		}
		delete query;
	}
	delete conn;

	return ok && result == 0 ? NoError : ExecFailed;
}

int32
VPokerSQL::doubleUpDeny(
	int32 casinoId, const PID& pid, VPokerGameID gid, uint8 machineID,
	bool8 forMoney, int32 creditValue,
	int32 payout,
	int32* balance, int32* comp)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;
	int32 result=0;

	conn = getConn();
	if (!conn)
		return NoConnection;
	
	query = conn->query();
	if (query)
	{
		query->define("exec pub_MHVPokerDblUpDeny ");
		query->addParam(casinoId);
		query->addParam(pid);
		query->addParam(machineID, ODBCQuery::BINARY);
		query->addParam((bool8)(forMoney != 0));
		query->addParam(creditValue);
		query->addParam(gid, ODBCQuery::NOQUOTES);
		query->addParam(payout, ODBCQuery::MONEY);

		if (query->exec())
		{
			while (query->getRow())
			{
				ok =
					query->getData(1, &result) &&
					query->getData(2, balance, ODBCQuery::MONEY) &&
					query->getData(3, comp);
			}
		}
		delete query;
	}
	delete conn;

	return ok && result == 0 ? NoError : ExecFailed;
}
int32 
VPokerSQL::setSubGameData(VPokerGameID gid, uint8 index, uint8 data)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;
	int32 result=0;

	conn = getConn();
	if (!conn)
		return NoConnection;
	
	query = conn->query();
	if (query)
	{
		query->define("exec pub_MHVPokerCreateSubGame ");
		query->addParam(gid);
		query->addParam(index);
		query->addParam(data);

		if (query->exec())
		{
			while (query->getRow())
			{
				ok =
					query->getData(1, &result);
			}
		}
		delete query;
	}
	delete conn;

	return ok && result == 0 ? NoError : ExecFailed;
}

bool8 
VPokerSQL::getSubGameData(VPokerGameID gid, uint8 index, uint8* data)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;
	bool8 result = false;
	uint8 tinyint;
	bool8 isnull = true;

	conn = getConn();
	if (!conn)
		return NoConnection;
	
	query = conn->query();
	if (query)
	{
		query->define("exec pub_MHVPokerGetSubGame ");
		query->addParam(gid);
		query->addParam(index);
		
		if (query->exec())
		{
			if (query->getRow())
			{
				ok =
					query->getData(1, &tinyint, &isnull);

				if (!isnull)
				{
					data[index] = tinyint;
					result = true;
				}
				else
				{
					data[index] = 0;
					result = false;
				}
			}
		}
		delete query;
	}
	delete conn;

	return result;
}



int32
VPokerSQL::doubleUpDeal(
	int32 casinoId, const PID& pid, VPokerGameID gid, bool8 forMoney,
	int32 round, uint8 dealt, ShueSave* shueSave,
	int32* balance, int32* comp)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;
	int32 result=0;

	conn = getConn();
	if (!conn)
		return NoConnection;
	
	query = conn->query();
	if (query)
	{
		query->define("exec pub_MHVPokerDblUpDeal ");
		query->addParam(casinoId);
		query->addParam(pid);
		query->addParam((bool8)(forMoney != 0));
		query->addParam(gid, ODBCQuery::NOQUOTES);
		query->addParam(round);
		query->addParam((int32)shueSave->seed);
		query->addParam(&dealt, 1, ODBCQuery::BINARY);

		if (query->exec())
		{
			while (query->getRow())
			{
				ok =
					query->getData(1, &result) &&
					query->getData(2, balance, ODBCQuery::MONEY) &&
					query->getData(3, comp);
			}
		}
		delete query;
	}
	delete conn;

	return ok && result == 0 ? NoError : ExecFailed;
}

int32
VPokerSQL::doubleUpDraw(
	int32 casinoId, const PID& pid, VPokerGameID gid, uint8 machineID,
	bool8 forMoney, int32 creditValue,
	int32 round, uint8 drawn, uint8 winResult, int32 payout,
	int32* balance, int32* comp)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;
	int32 result=0;

	conn = getConn();
	if (!conn)
		return NoConnection;
	
	query = conn->query();
	if (query)
	{
		query->define("exec pub_MHVPokerDblUpDraw ");
		query->addParam(casinoId);
		query->addParam(pid);
		query->addParam(machineID, ODBCQuery::BINARY);
		query->addParam((bool8)(forMoney != 0));
		query->addParam(creditValue);
		query->addParam(gid, ODBCQuery::NOQUOTES);
		query->addParam(round);
		query->addParam(&drawn, 1, ODBCQuery::BINARY);
		query->addParam(&winResult, 1, ODBCQuery::BINARY);
		query->addParam(payout, ODBCQuery::MONEY);

		if (query->exec())
		{
			while (query->getRow())
			{
				ok =
					query->getData(1, &result) &&
					query->getData(2, balance, ODBCQuery::MONEY) &&
					query->getData(3, comp);
			}
		}
		delete query;
	}
	delete conn;

	return ok && result == 0 ? NoError : ExecFailed;
}

int32
VPokerSQL::hasSavedGame(const PID& pid, uint8 machID, uint8 nHands, int32 creditValue,
	bool8 forMoney, VPokerGameID gid, VPokerSavedGame* dest, bool8* exists)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	*exists = false;

	conn = getConn();
	if (!conn)
		return NoConnection;
	
	query = conn->query();
	if (query)
	{
		query->define("exec pub_MHVPokerGetSavedGame ");
		query->addParam(pid);
		query->addParam(machID, ODBCQuery::BINARY);
		query->addParam(nHands);
		query->addParam(creditValue);
		query->addParam((bool8)(forMoney != 0));

		if (query->exec())
		{
			int32 hasSaved = 0;
			int16 smallint=0;
			int32 numcards=0, numcards2=0;
			int8 payfreq=0, tinyint=0;
			char lastDblUpOutcome[2];

			while (query->getRow())
			{
				ok = query->getData(1, &hasSaved);

				if (!ok)
					continue;

				switch (hasSaved)
				{
					case 0:	// no saved game of any kind
						break;
                    case 999:   
                    {
                        // kharmon.  10-06-06.  #15513.  There was a saved game, but it's incomplete for some reason.
                        // The stored procedure deleted the saved game record, so now the player can continue.  But, 
                        // first make in entry in the log noting this error.
                        char   gid[VPOKER_GAMEID_SIZE];
                        memset(gid, 0, sizeof(gid));
                        query->getData(2, gid, VPOKER_GAMEID_SIZE);

                        Log::msgError("A saved game could not be restored for gameid %s.", gid);
                        break;
                    }
					case 1: // vpoker saved game
						ok =
							query->getData(2, gid, VPOKER_GAMEID_SIZE) &&
							query->getData(3, &dest->bet, ODBCQuery::MONEY) &&
							query->getData(4, &dest->shue.seed) &&
							query->getData(5, &smallint) &&
							query->getData(6, dest->cards,
								VPokerSavedGame::MAXCARDS, &numcards) &&
							query->getData(7, &payfreq) &&
							query->getData(8, &tinyint); 

						if (ok)
						{
							ASSERT(numcards == VPokerSavedGame::MAXCARDS);
							dest->shue.next = smallint;
							dest->payFreq = payfreq;
							dest->dblUpEnabled = tinyint;
							dest->dblUpLastDealt[0] = 0;	// not used
							dest->dblUpLastOutcome = 0;		// not used
							dest->dblUpOrigPayType = 0;		// not used
							dest->dblUpPayType = 0;			// not used
							dest->dblUpPayout = 0;			// not used
							dest->dblUpWins = 0;			// not used
							dest->dblUpRound = 0;			// not used
							dest->kind = VPokerSavedGame::VPOKER_PLAYING;

							*exists = true;
						}
						break;

					case 2:	// dblup saved game...dblup available, 1st time
						ok =
							query->getData(2, gid, VPOKER_GAMEID_SIZE) &&
							query->getData(3, &dest->bet, ODBCQuery::MONEY) &&
							query->getData(4, &payfreq) &&
							query->getData(5, dest->dblUpLastDealt,
								VPokerSavedGame::MAXCARDS, &numcards);



						if (ok)
						{
							dest->kind = VPokerSavedGame::DBLUP_AVAIL_1ST;
							dest->payFreq = payfreq;
							dest->dblUpEnabled = 1;

							dest->shue.seed = 0;		// not used
							dest->shue.next = 0;		// not used
							dest->dblUpOrigPayType =0;
							dest->dblUpPayType = 0;
							dest->dblUpWins = 0;
							dest->dblUpRound = 0;
							dest->dblUpLastOutcome = 0;	// not used
							*exists = true;

						}
						break;

					case 3:	// dblup saved game...dblup available, not 1st time
						ok =
							query->getData(2, gid, VPOKER_GAMEID_SIZE) &&
							query->getData(3, &dest->bet,
								ODBCQuery::MONEY) &&
							query->getData(4, &payfreq) &&
							query->getData(5, &dest->shue.seed) &&
							query->getData(6, dest->cards,
								VPokerSavedGame::MAXCARDS, &numcards) &&
							query->getData(7, dest->cards + 1,
								VPokerSavedGame::MAXCARDS - 1, &numcards2) &&
							query->getData(8, &dest->dblUpPayout,
								ODBCQuery::MONEY) &&
							query->getData(9, lastDblUpOutcome, 2) &&
							query->getData(10, &dest->dblUpWins) &&
							query->getData(11, &tinyint);


						if (ok)
						{
							ASSERT(numcards == 1);
							ASSERT(numcards2 == 1);

							dest->dblUpLastOutcome = lastDblUpOutcome[0];
							dest->payFreq = payfreq;
							dest->dblUpRound = tinyint;
							dest->dblUpEnabled = 1;
							dest->shue.next = 0;
							dest->dblUpLastDealt[0] = 0;	// not used
							dest->dblUpPayType = 0;			// not used
							dest->kind = VPokerSavedGame::DBLUP_AVAIL_NOT1ST;

							*exists = true;
						}
						break;

					case 4:	// dblup saved game...dealt, 1st time
					case 5:	// dblup saved game...dealt, not 1st time
						ok =
							query->getData(2, gid, VPOKER_GAMEID_SIZE) &&
							query->getData(3, &dest->bet,
								ODBCQuery::MONEY) &&
							query->getData(4, &payfreq) &&
							query->getData(5, &dest->shue.seed) &&
							query->getData(6, dest->cards,
								VPokerSavedGame::MAXCARDS, &numcards) &&
							query->getData(7, &dest->dblUpPayout,
								ODBCQuery::MONEY) &&
							query->getData(8, lastDblUpOutcome, 2) &&
							query->getData(9, &dest->dblUpWins) &&
							query->getData(10, &tinyint);

						if (ok)
						{
							ASSERT(numcards == 1);

							dest->dblUpLastOutcome = lastDblUpOutcome[0];
							dest->payFreq = payfreq;
							dest->dblUpRound = tinyint;
							dest->dblUpEnabled = 1;
							dest->shue.next = 0;
							dest->dblUpLastDealt[0] = 0;	// not used
							dest->dblUpPayType = 0;			// not used
							dest->kind = VPokerSavedGame::DBLUP_PLAYING;

							*exists = true;
						}
						break;

					default:
						ok = false;
						break;
				}
			}
		}
		delete query;
	}
	delete conn;

	return ok ? NoError : ExecFailed;
}

int32
VPokerSQL::getDrawnCards(VPokerGameID gid, uint8 cards[100][5], int32 *payouts, int32 *paytypes, int32 *savhands  )
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;
	int32 n = 0;

	conn = getConn();
	if (!conn)
		return NoConnection;
	
	query = conn->query();
	if (query)
	{
		query->define("exec pub_MHVPokerGetDrawnHands ");
		query->addParam(gid, ODBCQuery::NOQUOTES);

		if (query->exec())
		{
			while (query->getRow())
			{
				int32 numcards=0;
				int8 hand=0;
				ok=query->getData(1, &hand);
				if( ok )
				{
					ok = query->getData(2,cards[hand],VPokerSavedGame::MAXCARDS,&numcards) &&
						query->getData(3, &payouts[hand],ODBCQuery::MONEY) &&
						query->getData(4, &paytypes[hand]);
				}
				ASSERT(numcards == VPokerSavedGame::MAXCARDS);

				if( ok ) n++;

				else break;
			}
		}
		delete query;
	}

	delete conn;

	*savhands = n;

	return ok ? NoError : ExecFailed;
}
